package org.sunrise.game.client.client;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import io.netty.channel.ChannelHandlerContext;
import org.sunrise.game.ClientStartUp;
import org.sunrise.game.client.gen.ChatProto;
import org.sunrise.game.client.gen.HumanProto;
import org.sunrise.game.client.gen.LoginProto;
import org.sunrise.game.client.gen.MapProto;
import org.sunrise.game.client.gen.TopicProto;
import org.sunrise.game.common.log.LogCore;

public class ClientMessageHandler {
    public static void handler(SocketClient client, ChannelHandlerContext ctx, byte[] data) {
        try {
            TopicProto.MBasePacketData msg = TopicProto.MBasePacketData.parseFrom(data);
            TopicProto.TOPIC packetType = msg.getPacketType();
            int packetId = msg.getPacketId();

            if (packetType == TopicProto.TOPIC.TOPIC_TYPE_LOGIN) {
                handleLogin(client, packetId, msg.getPacketData());
            } else if (packetType == TopicProto.TOPIC.TOPIC_TYPE_MAP) {
                handleMapMessages(client, packetId, msg.getPacketData());
            } else if (packetType == TopicProto.TOPIC.TOPIC_TYPE_HUMAN) {
                if (packetId == HumanProto.FROM_SERVER.S2C_HumanInfo_VALUE) {
                    HumanProto.MS2C_HumanInfo ms2CHumanInfo = HumanProto.MS2C_HumanInfo.parseFrom(msg.getPacketData());
                    client.setHumanId(ms2CHumanInfo.getHumanId());
                    ClientStartUp.myHumanId = ms2CHumanInfo.getHumanId();
                    client.setStartSend(true);
                }
            } else if (packetType == TopicProto.TOPIC.TOPIC_TYPE_CHAT) {
                handleChatMessages(client, packetId, msg.getPacketData());
            }
            if (packetType == TopicProto.TOPIC.TOPIC_TYPE_LOGIN && packetId == 5) {
                ctx.close();
            }
        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }
    }

    private static void handleLogin(SocketClient client, int packetId, ByteString packetData) throws InvalidProtocolBufferException {
        if (packetId == 0) {
            client.sendMsg(TopicProto.MBasePacketData.newBuilder()
                    .setPacketType(TopicProto.TOPIC.TOPIC_TYPE_LOGIN)
                    .setPacketId(LoginProto.FROM_CLIENT.C2S_HumanList_VALUE)
                    .build());
        } else if (packetId == 1) {
            client.sendMsg(TopicProto.MBasePacketData.newBuilder()
                    .setPacketType(TopicProto.TOPIC.TOPIC_TYPE_LOGIN)
                    .setPacketId(LoginProto.FROM_CLIENT.C2S_SelectHuman_VALUE)
                    .setPacketData(LoginProto.MC2S_SelectHuman.newBuilder().setPos(0).setServerId(1).build().toByteString())
                    .build());
        } else if (packetId == 2) {
            LogCore.Client.info("login success, uid = {}, use = {} ms", client.getUid(), System.currentTimeMillis() - client.getLoginStartTime());
        } else if (packetId == 3) {
            client.setRecvCount(client.getRecvCount() + 1);
            LogCore.Client.info("recv ping, delay = {} ms, RecvCount = {}, SendCount = {}", System.currentTimeMillis() - client.getPingStartTime(), client.getRecvCount(), client.getSendCount());
        }
    }

    private static void handleMapMessages(SocketClient client, int packetId, ByteString packetData) throws InvalidProtocolBufferException {
        if (packetId == MapProto.FROM_SERVER.S2C_Enter_VALUE) {
            MapProto.MS2C_Enter enterData = MapProto.MS2C_Enter.parseFrom(packetData);
            MapProto.STRoleInfo newPlayer = enterData.getNewPlayer();
            // 更新其他玩家进入逻辑，比如将其添加到玩家列表中
            addPlayer(client, newPlayer.getHumanId(), newPlayer.getName(), newPlayer.getMapPostX(), newPlayer.getMapPostY());
        } else if (packetId == MapProto.FROM_SERVER.S2C_Move_VALUE) {
            MapProto.MS2C_Move moveData = MapProto.MS2C_Move.parseFrom(packetData);
            String movingPlayerId = moveData.getHumanId();
            updatePlayerPosition(client, movingPlayerId, moveData.getMapPostX(), moveData.getMapPostY());
        } else if (packetId == MapProto.FROM_SERVER.S2C_Sync_VALUE) {
            MapProto.MS2C_Sync moveData = MapProto.MS2C_Sync.parseFrom(packetData);
            for (MapProto.STRoleInfo role : moveData.getRolesList()) {
                addPlayer(client, role.getHumanId(), role.getName(), role.getMapPostX(), role.getMapPostY());
            }
        } else if (packetId == MapProto.FROM_SERVER.S2C_Leave_VALUE) {
            MapProto.MS2C_Leave leaveData = MapProto.MS2C_Leave.parseFrom(packetData);
            String leavingPlayerId = leaveData.getHumanId();
            removePlayer(client, leavingPlayerId);
        } else if (packetId == MapProto.FROM_SERVER.S2C_LastMap_VALUE) {
            MapProto.MS2C_LastMap ms2CLastMap = MapProto.MS2C_LastMap.parseFrom(packetData);
            System.out.println(ms2CLastMap);
        }
    }

    private static void handleChatMessages(SocketClient client, int packetId, ByteString packetData) throws InvalidProtocolBufferException {
        if (packetId == ChatProto.FROM_SERVER.S2C_Chat_VALUE) {
            ChatProto.MS2C_Chat data = ChatProto.MS2C_Chat.parseFrom(packetData);
            System.out.println(data);
        }
    }

    private static void addPlayer(SocketClient client, String playerId, String name, int x, int y) {
        PlayerInfo playerInfo = ClientStartUp.otherPlayers.get(playerId);
        if (playerInfo == null) {
            PlayerInfo newPlayer = new PlayerInfo(playerId, (float) x, (float) y, name);
            ClientStartUp.otherPlayers.put(playerId, newPlayer);
        } else {
            playerInfo.setTargetPosition(x,y);
        }
    }


    private static void updatePlayerPosition(SocketClient client, String playerId, int x, int y) {
        PlayerInfo playerInfo = ClientStartUp.otherPlayers.get(playerId);
        if (playerInfo != null) {
            playerInfo.setTargetPosition((float) x, (float) y);
        }
    }

    private static void removePlayer(SocketClient client, String playerId) {
        ClientStartUp.otherPlayers.remove(playerId);
    }
}
